﻿#include "VulkanTextWidget.h"
#include "Render/VulkanContext.h"
#include "Render/Widget/VulkanWindow.h"

#include "Shaders/CppMacros.h"

#include "Render/VulkanMemory/Buffers.h"
#include "Render/PreRender/PreRenderTexture2D.h"
#include "Render/Texture/VulkanTexture2D.h"

CVulkanTextWidgets::~CVulkanTextWidgets()
{
    //销毁command buffer
    CVulkanContext::Get()->GetRecycleObjects()->CommandBuffers.Add(CommandBuffer);
}

void CVulkanTextWidgets::PreProcess(const TVector<SPreRenderTextWidget> &AllTextData)
{
    TVector<SPreRenderTextWidget> ValidData;
    ValidData.Reserve(AllTextData.Num());

    for (auto& TextData : AllTextData)
    {
        ValidData.Add(TextData);
    };

    //创建渲染对象
    TextWidgets.Resize(ValidData.Num());
    for (int i = 0; i < ValidData.Num(); ++i)
    {
        TextWidgets[i].BindData(ValidData[i]);
    }

    //统计描述符
    for(auto& TextWidget: TextWidgets)
    {
        TextWidget.CountDescriptorNum();
    }

}

void CVulkanTextWidgets::CreateSelfRecordTasks(CVulkanWindow *InRenderSurface, SRenderCommandBuffers &OutCmdBuffersToExecute)
{
    if(TextWidgets.Num()==0)
    {
        return;
    }

    //创建command buffer
    if(!CommandBuffer)
    {
        //allocate a command buffer for this widget
        vk::CommandBufferAllocateInfo CommandBufferAllocateInfo=vk::CommandBufferAllocateInfo()
            .setCommandPool(CVulkanContext::Get()->GetRenderThreadCommandPool())
            .setLevel(vk::CommandBufferLevel::eSecondary)
            .setCommandBufferCount(1);

        CommandBuffer = CVulkanContext::Get()->GetDevice().allocateCommandBuffers(CommandBufferAllocateInfo)[0];
    }


    OutCmdBuffersToExecute.TextImageWidgetRenderPassCommandBuffers.Add(CommandBuffer);

    vk::CommandBufferInheritanceInfo CommandBufferInheritanceInfo=vk::CommandBufferInheritanceInfo()
        .setRenderPass(CVulkanContext::Get()->GetWidgetRenderPass())
        .setFramebuffer(InRenderSurface->GetCurrentFrameBuffer())
        .setSubpass(0)
    ;

    vk::CommandBufferBeginInfo CommandBufferBeginInfo=vk::CommandBufferBeginInfo()
        .setFlags(vk::CommandBufferUsageFlagBits::eRenderPassContinue)
        .setPInheritanceInfo(&CommandBufferInheritanceInfo);

    CommandBuffer.begin(CommandBufferBeginInfo);
    //绑定pipeline
    CommandBuffer.bindPipeline(
        vk::PipelineBindPoint::eGraphics
        ,CVulkanContext::Get()->GetTextWidgetPipeline()->DynamicPipeline
        );    

    for (auto& TextWidget : TextWidgets)
    {
        TextWidget.Draw(CommandBuffer);
    }

    CommandBuffer.end();

}

void CVulkanTextWidget::BindData(const SPreRenderTextWidget& InData)
{
    Depth=InData.Depth;
    Viewport=InData.Viewport;
    Scissor=InData.Scissor;
    TextImage=CVulkanContext::Get()->ToVulkanTexture2D(InData.TextImage->Pixels);
    CharData=InData.CharData;


    if(!UniformBuffer)
    {
        UniformBuffer = std::make_shared<CVulkanUniformBuffer>();
    }

    int32_t UniformBufferDataSize=
        sizeof(SCharUniformBufferData)
        * CharData.Num();
    UniformBuffer->Resize(UniformBufferDataSize);
    UniformBuffer->WriteData(CharData.Data(),UniformBufferDataSize);

}

void CVulkanTextWidget::Draw(vk::CommandBuffer CommandBuffer)
{
   
    CommandBuffer.setViewport(0,1,&Viewport);
    CommandBuffer.setScissor(0,1,&Scissor);



    //创建并绑定描述符集
    //1.创建描述符集
    TVector<vk::DescriptorSetLayout> DescriptorSetLayouts=
    {
        CVulkanContext::Get()->GetTextWidgetPipeline()->DynamicDescriptorSetLayout.Layout
    };


    int32_t BatchNum= CharData.Num()/CHAR_BATCH_SIZE;
    if(CharData.Num()%CHAR_BATCH_SIZE!=0)
    {
        ++BatchNum;
    }

    //推送常量
    STextWidgetPipeline::SDynamicTextPushConstant PushConstantValue;
    PushConstantValue.ZOrder=Depth;
    
    CommandBuffer.pushConstants(
        CVulkanContext::Get()->GetTextWidgetPipeline()->DynamicPipelineLayout
        ,vk::ShaderStageFlagBits::eVertex
        ,0
        ,sizeof(PushConstantValue)
        ,&PushConstantValue);
    

    for(int32_t BatchIndex=0; BatchIndex<BatchNum;++BatchIndex)
    {
        //这个小批次的大小
        int32_t BatchSize=
            CMath::Min(CHAR_BATCH_SIZE,CharData.Num()-BatchIndex*CHAR_BATCH_SIZE);


        vk::DescriptorSetAllocateInfo DescriptorSetAllocateInfo = vk::DescriptorSetAllocateInfo()
            .setDescriptorPool(CVulkanContext::Get()->GetAutoResetDescriptorPool()->GenerallPool.Pool)
            .setSetLayouts(DescriptorSetLayouts);
    
        auto DescriptorSet = CVulkanContext::Get()->GetDevice().allocateDescriptorSets(DescriptorSetAllocateInfo)[0];
        DescriptorSets.Add(DescriptorSet);

        //2.写入描述符
        TVector<vk::DescriptorImageInfo> DescriptorTexture2DInfos=
        {
            vk::DescriptorImageInfo()
                .setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
                .setImageView(TextImage->ImageView)
                .setSampler(
                    CVulkanContext::Get()->GetTextWidgetPipeline()->TextImageSampler
                )
        };
     

        vk::DescriptorBufferInfo DescriptorBufferInfo = vk::DescriptorBufferInfo()
            .setBuffer(UniformBuffer->GetBuffer())
            .setOffset(BatchIndex*CHAR_BATCH_SIZE*sizeof(SCharUniformBufferData))
            .setRange(BatchSize*sizeof(SCharUniformBufferData));

        TVector<vk::WriteDescriptorSet> WriteDescriptorSets=
        {
            vk::WriteDescriptorSet()
                .setDstSet(DescriptorSet)
                .setDstBinding(0)
                .setDstArrayElement(0)
                .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
                .setDescriptorCount(DescriptorTexture2DInfos.Num())
                .setPImageInfo(DescriptorTexture2DInfos.Data())
            ,
            vk::WriteDescriptorSet()
                .setDstSet(DescriptorSet)
                .setDstBinding(1)
                .setDstArrayElement(0)
                .setDescriptorType(vk::DescriptorType::eUniformBuffer)
                .setDescriptorCount(1)
                .setPBufferInfo(&DescriptorBufferInfo)
            ,

        };

        CVulkanContext::Get()->GetDevice().updateDescriptorSets(WriteDescriptorSets, nullptr);
   
        //3.绑定描述符集
        CommandBuffer.bindDescriptorSets(
            vk::PipelineBindPoint::eGraphics
            ,CVulkanContext::Get()->GetTextWidgetPipeline()->DynamicPipelineLayout
            ,0
            ,1
            ,&DescriptorSet
            ,0
            ,nullptr);
        
        CommandBuffer.draw(
            4
            ,BatchSize
            ,0
            ,0);    
    }
}

void CVulkanTextWidget::CountDescriptorNum()
{
    SVulkanDescriptorPoolSize PoolSize;
    int32_t BatchNum=CharData.Num()/ CHAR_BATCH_SIZE;
    if(CharData.Num()%CHAR_BATCH_SIZE!=0)
    {
        ++BatchNum;
    }

    PoolSize.SetNum=BatchNum;
    PoolSize+=
        CVulkanContext::Get()->GetTextWidgetPipeline()->DynamicDescriptorSetLayout.DescriptorNums * BatchNum;
    CVulkanContext::Get()->GetAutoResetDescriptorPool()->GenerallPool.PoolSize+=PoolSize;
}
